package org.jsola.hr.service.impl;

import com.alibaba.fastjson.JSON;
import org.apache.commons.lang3.StringUtils;
import org.jsola.hr.common.AttendKit;
import org.jsola.hr.constant.HrConstants;
import org.jsola.hr.dto.AttendShiftAddDTO;
import org.jsola.hr.dto.AttendShiftScheduleCycleAddDTO;
import org.jsola.hr.dto.AttendShiftStaffScheduleAddDTO;
import org.jsola.hr.dto.attendschedule.*;
import org.jsola.hr.entity.AttendPunchRecordDO;
import org.jsola.hr.entity.AttendShiftDO;
import org.jsola.hr.entity.AttendShiftScheduleCycleDO;
import org.jsola.hr.entity.AttendShiftStaffScheduleDO;
import org.jsola.hr.query.AttendPunchRecordQuery;
import org.jsola.hr.query.AttendShiftQuery;
import org.jsola.hr.query.AttendShiftScheduleCycleQuery;
import org.jsola.hr.query.AttendShiftStaffScheduleQuery;
import org.jsola.hr.service.*;
import org.jsola.hr.vo.attendschedule.AttendScheduleVO;
import org.jsola.hr.vo.attendschedule.AttendShiftVO;
import org.jsola.log.common.LogKit;
import org.jsola.user.core.TokenUser;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.ArrayList;
import java.util.List;
import java.util.UUID;

/**
 * 考勤排班
 *
 * @author wxz
 */
@Service("hrAttendScheduleServiceImpl")
public class AttendScheduleServiceImpl implements IAttendScheduleService {

    @Autowired
    private IAttendShiftService attendShiftService;
    @Autowired
    private IAttendShiftScheduleCycleService attendShiftScheduleCycleService;
    @Autowired
    private IAttendShiftStaffScheduleService attendShiftStaffScheduleService;
    @Autowired
    private IAttendPunchRecordService attendPunchRecordService;

    @Override
    @Transactional(value = HrConstants.TX, rollbackFor = Exception.class)
    public String save(AttendScheduleSaveDTO attendScheduleSaveDTO, TokenUser tokenUser) {

        String scheduleId = UUID.randomUUID().toString().replace("-", "");

        List<AttendShiftSaveDTO> attendShiftLst = attendScheduleSaveDTO.getAttendShiftList();
        if (attendShiftLst != null && attendShiftLst.size() > 0) {
            for (int i = 0; i < attendShiftLst.size(); i++) {
                AttendShiftSaveDTO attendShiftSaveDTO = attendShiftLst.get(i);
                if (attendShiftSaveDTO.getRestPeriod() != null) {
                    attendShiftSaveDTO.getAttendPeriodList().add(attendShiftSaveDTO.getRestPeriod());
                }
            }
        }

        // 保存考勤班次
        List<AttendShiftSaveDTO> attendShiftList = attendScheduleSaveDTO.getAttendShiftList();
        if (attendShiftList != null && attendShiftList.size() > 0) {

            for (int i = 0; i < attendShiftList.size(); i++) {

                AttendShiftSaveDTO attendShift = attendShiftList.get(i);
                // 校验打卡时段
                AttendKit.validAttendPeriod(attendShift.getAttendPeriodList());

                // 初始化高级设置
                // 允许迟到早退 ; 1-允许,0-不允许
                if (attendShift.getIsAllowedLateEarly() == null) {
                    attendShift.setIsAllowedLateEarly(0);
                }
                // 上班允许迟到(分钟)
                if (attendShift.getLateMinute() == null) {
                    attendShift.setLateMinute(0);
                }
                // 班允许早退(分钟)
                if (attendShift.getEarlyMinute() == null) {
                    attendShift.setEarlyMinute(0);
                }
                // 允许晚走晚到 ; 1-允许,0-不允许
                if (attendShift.getIsAllowLateLate() == null) {
                    attendShift.setIsAllowLateLate(0);
                }
                // 下班晚走(分钟)
                if (attendShift.getOffWorkLateMinute() == null) {
                    attendShift.setOffWorkLateMinute(0);
                }
                // 上班晚到(分钟)
                if (attendShift.getOnWorkLateMinute() == null) {
                    attendShift.setOnWorkLateMinute(0);
                }
                // 最早上班打卡时间(分钟)
                if (StringUtils.isBlank(attendShift.getEarliestPunchTime())) {
                    attendShift.setEarliestPunchTime("0");
                }
                // 最晚下班打卡时间(分钟)
                if (StringUtils.isBlank(attendShift.getLatestPunchTime())) {
                    attendShift.setLatestPunchTime("0");
                }
                // 班是否需要打卡 : 1-是,0-否
                if (attendShift.getAfterWorkNeedPunch() == null) {
                    attendShift.setAfterWorkNeedPunch(0);
                }
            }
        }

        this.saveAttendShift(scheduleId, attendShiftList, tokenUser);

        // 保存排班周期
        List<AttendCycleSaveDTO> attendCycleList = attendScheduleSaveDTO.getAttendCycleList();
        this.saveAttendCycle(scheduleId, attendCycleList, tokenUser);

        // 保存人员排班
        List<AttendStaffScheduleDTO> attendStaffScheduleList = attendScheduleSaveDTO.getAttendStaffScheduleList();
        this.saveAttendStaffSchedule(scheduleId, attendStaffScheduleList, tokenUser);

        LogKit.logForSave("保存考勤排班, 主键ID：" + scheduleId, "attendPlan", tokenUser);

        return scheduleId;
    }

    /**
     * 修改考勤排班
     *
     * @param attendScheduleUpdateDTO
     * @param tokenUser
     * @return
     */
    @Override
    public int update(AttendScheduleUpdateDTO attendScheduleUpdateDTO, TokenUser tokenUser) {

        // 删除考勤班次
        attendShiftService.deleteByAttendPlanId(attendScheduleUpdateDTO.getAttendPlanId(), tokenUser);
        // 删除排班周期
        attendShiftScheduleCycleService.deleteByAttendPlanId(attendScheduleUpdateDTO.getAttendPlanId(), tokenUser);
        // 删除人员排班
        attendShiftStaffScheduleService.deleteByAttendPlanId(attendScheduleUpdateDTO.getAttendPlanId(), tokenUser);

        List<AttendShiftSaveDTO> attendShiftLst = attendScheduleUpdateDTO.getAttendShiftList();
        if (attendShiftLst != null && attendShiftLst.size() > 0) {
            for (int i = 0; i < attendShiftLst.size(); i++) {
                AttendShiftSaveDTO attendShiftSaveDTO = attendShiftLst.get(i);
                if (attendShiftSaveDTO.getRestPeriod() != null) {
                    attendShiftSaveDTO.getAttendPeriodList().add(attendShiftSaveDTO.getRestPeriod());
                }
            }
        }

        // 保存考勤班次
        this.saveAttendShift(attendScheduleUpdateDTO.getAttendPlanId(), attendScheduleUpdateDTO.getAttendShiftList(), tokenUser);
        // 保存排班周期
        this.saveAttendCycle(attendScheduleUpdateDTO.getAttendPlanId(), attendScheduleUpdateDTO.getAttendCycleList(), tokenUser);
        // 保存人员排班
        this.saveAttendStaffSchedule(attendScheduleUpdateDTO.getAttendPlanId(), attendScheduleUpdateDTO.getAttendStaffScheduleList(), tokenUser);

        LogKit.logForUpdate("修改考勤排班, 主键ID:" + attendScheduleUpdateDTO.getAttendPlanId(), "attendPlan", tokenUser);

        return 1;
    }

    @Override
    public AttendScheduleVO selectAttendPlanId(String attendPlanId, String siteId) {

        AttendScheduleVO attendScheduleVO = new AttendScheduleVO();

        // 考勤班次
        List<AttendShiftVO> attendShiftList = new ArrayList<>();
        // 排班周期
        List<AttendCycleSaveDTO> attendCycleList = new ArrayList<>();
        // 人员排班
        List<AttendStaffScheduleDTO> attendStaffScheduleList = new ArrayList<>();

        // 查询考勤班次
        AttendShiftQuery attendShiftQuery = new AttendShiftQuery();
        attendShiftQuery.setAttendPlanId(attendPlanId);
        List<AttendShiftDO> attendShiftDOList = attendShiftService.selectDO(attendShiftQuery, siteId);
        if (attendShiftDOList != null && attendShiftDOList.size() > 0) {
            for (AttendShiftDO attendShiftDO : attendShiftDOList) {
                AttendShiftVO attendShiftVO = attendShiftDO.to(AttendShiftVO.class);

                List<AttendPeriodDTO> attendPeriodList = JSON.parseArray(attendShiftDO.getPeriodJson(), AttendPeriodDTO.class);
                List<AttendPeriodDTO> newAttendPeriodList = new ArrayList<>();
                if (attendPeriodList != null) {
                    for (int i = 0; i < attendPeriodList.size(); i++) {
                        AttendPeriodDTO attendPeriodDTO = attendPeriodList.get(i);
                        if (attendPeriodDTO.getType() == 2) {
                            attendShiftVO.setRestPeriod(attendPeriodDTO);
                        }
                        else {
                            newAttendPeriodList.add(attendPeriodDTO);
                        }
                    }
                }

                attendShiftVO.setAttendPeriodList(newAttendPeriodList);

                attendShiftVO.setIsAdvanc(attendShiftDO.getIsAdvanc());
                attendShiftList.add(attendShiftVO);
            }
        }

        // 查询排班周期
        AttendShiftScheduleCycleQuery attendShiftScheduleCycleQuery = new AttendShiftScheduleCycleQuery();
        attendShiftScheduleCycleQuery.setAttendPlanId(attendPlanId);
        List<AttendShiftScheduleCycleDO> attendShiftScheduleCycleDOList = attendShiftScheduleCycleService.selectDO(attendShiftScheduleCycleQuery, siteId);
        if (attendShiftScheduleCycleDOList != null && attendShiftScheduleCycleDOList.size() > 0) {
            for (AttendShiftScheduleCycleDO attendShiftScheduleCycleDO : attendShiftScheduleCycleDOList) {
                AttendCycleSaveDTO attendCycleSaveDTO = new AttendCycleSaveDTO();
                attendCycleSaveDTO.setCycleName(attendShiftScheduleCycleDO.getName());
                attendCycleSaveDTO.setCycleDays(JSON.parseArray(attendShiftScheduleCycleDO.getDaysJson(), CycleDaysDTO.class));
                attendCycleList.add(attendCycleSaveDTO);
            }
        }
        
        // 查询人员排班
        AttendShiftStaffScheduleQuery attendShiftStaffScheduleQuery = new AttendShiftStaffScheduleQuery();
        attendShiftStaffScheduleQuery.setAttendPlanId(attendPlanId);
        List<AttendShiftStaffScheduleDO> attendShiftStaffScheduleDOList = attendShiftStaffScheduleService.selectDO(attendShiftStaffScheduleQuery, siteId);
        if (attendShiftStaffScheduleDOList != null && attendShiftStaffScheduleDOList.size() > 0) {
            for (AttendShiftStaffScheduleDO attendShiftStaffScheduleDO : attendShiftStaffScheduleDOList) {

                AttendStaffScheduleDTO attendStaffScheduleDTO = new AttendStaffScheduleDTO();

                attendStaffScheduleDTO.setEmpInfoId(attendShiftStaffScheduleDO.getEmpInfoId());
                // attendStaffScheduleDTO.setEmpInfoName();
                attendStaffScheduleDTO.setShiftName(attendShiftStaffScheduleDO.getAttendShiftName());
                attendStaffScheduleDTO.setYearMonthDay(attendShiftStaffScheduleDO.getYearly()
                                                            + "-" + attendShiftStaffScheduleDO.getMonthly()
                                                            + "-" + attendShiftStaffScheduleDO.getDaily());

                attendStaffScheduleDTO.setType(attendShiftStaffScheduleDO.getType());
                attendStaffScheduleList.add(attendStaffScheduleDTO);
            }
        }


        attendScheduleVO.setAttendShiftList(attendShiftList);
        attendScheduleVO.setAttendCycleList(attendCycleList);
        attendScheduleVO.setAttendStaffScheduleList(attendStaffScheduleList);

        return attendScheduleVO;
    }

    /**
     * 保存考勤规则的时候更新考勤班次的考勤规则ID
     *
     * @param tmpAttendPlanId 临时考勤规则ID
     * @param attendPlanId 考勤规则ID
     * @param tokenUser 当前用户
     * @return
     */
    @Override
    public int saveRuleForSchedule(String tmpAttendPlanId, String attendPlanId, TokenUser tokenUser) {

        // 更新考勤班次
        attendShiftService.updateAttendPlanId(tmpAttendPlanId, attendPlanId, tokenUser);

        // 更新排班周期
        attendShiftScheduleCycleService.updateAttendPlanId(tmpAttendPlanId, attendPlanId, tokenUser);

        // 更新考勤人员排班
        attendShiftStaffScheduleService.updateAttendPlanId(tmpAttendPlanId, attendPlanId, tokenUser);

        return 1;
    }

    @Override
    public int resetTodayPunchRecord(String attendPlanId, String attendDateStr, TokenUser tokenUser) {

        // 查询考勤日使用的考勤班次
        AttendShiftStaffScheduleQuery attendShiftStaffScheduleQuery = new AttendShiftStaffScheduleQuery();

        attendShiftStaffScheduleQuery.setAttendPlanId(attendPlanId);
        attendShiftStaffScheduleQuery.setYearly(attendDateStr.split("-")[0]);
        attendShiftStaffScheduleQuery.setMonthly(attendDateStr.split("-")[1]);
        attendShiftStaffScheduleQuery.setDaily(attendDateStr.split("-")[2]);

        List<AttendShiftStaffScheduleDO> attendShiftStaffScheduleList = attendShiftStaffScheduleService.selectDO(attendShiftStaffScheduleQuery, tokenUser.getSiteId());
        if (attendShiftStaffScheduleList.size() <= 0) {
            return 0;
        }

        List<String> shiftNameList = new ArrayList<>();

        for (AttendShiftStaffScheduleDO attendShiftStaffSchedule : attendShiftStaffScheduleList) {
            shiftNameList.add(attendShiftStaffSchedule.getAttendShiftName());
        }

        // 查询考勤班次
        AttendShiftQuery attendShiftQuery = new AttendShiftQuery();
        attendShiftQuery.setAttendPlanId(attendPlanId);
        attendShiftQuery.setNameList(shiftNameList);
        List<AttendShiftDO> attendShiftList = attendShiftService.selectDO(attendShiftQuery, tokenUser.getSiteId());

        // 查询考勤日期所有的打卡记录
        AttendPunchRecordQuery attendPunchRecordQuery = new AttendPunchRecordQuery();
        attendPunchRecordQuery.setAttendPlanId(attendPlanId);
        attendPunchRecordQuery.setYear(attendDateStr.split("-")[0]);
        attendPunchRecordQuery.setMonth(attendDateStr.split("-")[1]);
        attendPunchRecordQuery.setDay(attendDateStr.split("-")[2]);
        List<AttendPunchRecordDO> attendPunchRecordList = attendPunchRecordService.selectDO(attendPunchRecordQuery, tokenUser.getSiteId());
        if (attendPunchRecordList.size() <= 0) {
            return 0;
        }

        // 遍历每条考勤记录，重新考勤
        for (int i = 0; i < attendPunchRecordList.size(); i++) {

            AttendPunchRecordDO attendPunchRecordDO = attendPunchRecordList.get(i);

            if (attendPunchRecordDO.getPunchType() == 0) {
                continue;
            }

            // 查询使用的考勤班次
            AttendShiftSaveDTO attendShiftSaveDTO = attendShiftService.getAttendShift(attendPunchRecordDO.getAttendPlanId(), attendPunchRecordDO.getEmpInfoId(), attendDateStr, tokenUser);
            if (attendShiftSaveDTO == null) {
                continue;
            }

            // 考勤时间段
            List<AttendPeriodDTO> attendPeriodList = attendShiftSaveDTO.getAttendPeriodList();

            // 查询打卡的时间段
            AttendPeriodDTO inAttendPeriod = null;

            if (attendPeriodList != null && attendPeriodList.size() > 0) {
                for (AttendPeriodDTO attendPeriod : attendPeriodList) {

                    if (StringUtils.isNotBlank(attendPunchRecordDO.getPunchSerial())) {
                        int punchSerial = Integer.valueOf(attendPunchRecordDO.getPunchSerial()).intValue();
                        if (punchSerial == attendPeriod.getSort()) {
                            inAttendPeriod = attendPeriod;
                            break;
                        }
                    }
                }
            }

            // 如果没有查询到使用的打卡时段，则将考勤记录设置为异常状态
            if (inAttendPeriod == null) {
                AttendPunchRecordDO record = new AttendPunchRecordDO();

                record.setId(attendPunchRecordDO.getId());
                record.setPunchStatus(6);
//                record.setHisStandardTime(attendPunchRecordDO.getStandardTime());
                record.setHisPunchTime(attendPunchRecordDO.getPunchTime());
                record.setHisPunchStatus(attendPunchRecordDO.getPunchStatus());

                attendPunchRecordService.updateByIdSelective(record, tokenUser.getSiteId(), tokenUser.getUserId());
            }
            else {

//                int punchTimeInt = Integer.valueOf(attendPunchRecordDO.getPunchTime().replace(":", "")).intValue();
                int punchTimeInt = 0;
                // 上班还是下班
                if (attendPunchRecordDO.getPunchType() == 1) {
                    int onWorkInt = Integer.valueOf(inAttendPeriod.getStartPeriod().replace(":", "")).intValue();

                    // 正常
                    if (punchTimeInt <= onWorkInt) {

                        AttendPunchRecordDO record = new AttendPunchRecordDO();
                        record.setId(attendPunchRecordDO.getId());
                        record.setPunchStatus(1);
//                        record.setStandardTime(inAttendPeriod.getStartPeriod());
//                        record.setHisStandardTime(attendPunchRecordDO.getStandardTime());
                        record.setHisPunchTime(attendPunchRecordDO.getPunchTime());
                        record.setHisPunchStatus(attendPunchRecordDO.getPunchStatus());

                        attendPunchRecordService.updateByIdSelective(record, tokenUser.getSiteId(), tokenUser.getUserId());
                    }
                    // 上班迟到 - 异常
                    else {
                        AttendPunchRecordDO record = new AttendPunchRecordDO();
                        record.setId(attendPunchRecordDO.getId());
                        record.setPunchStatus(6);
//                        record.setStandardTime(inAttendPeriod.getStartPeriod());
//                        record.setHisStandardTime(attendPunchRecordDO.getStandardTime());
                        record.setHisPunchTime(attendPunchRecordDO.getPunchTime());
                        record.setHisPunchStatus(attendPunchRecordDO.getPunchStatus());

                        attendPunchRecordService.updateByIdSelective(record, tokenUser.getSiteId(), tokenUser.getUserId());
                    }
                }
                else if (attendPunchRecordDO.getPunchType() == 2) {
                    int offWorkInt = Integer.valueOf(inAttendPeriod.getEndPeriod().replace(":", "")).intValue();

                    // 早退 - 异常
                    if (punchTimeInt < offWorkInt) {
                        AttendPunchRecordDO record = new AttendPunchRecordDO();
                        record.setId(attendPunchRecordDO.getId());
                        record.setPunchStatus(6);
//                        record.setStandardTime(inAttendPeriod.getEndPeriod());
//                        record.setHisStandardTime(attendPunchRecordDO.getStandardTime());
                        record.setHisPunchTime(attendPunchRecordDO.getPunchTime());
                        record.setHisPunchStatus(attendPunchRecordDO.getPunchStatus());

                        attendPunchRecordService.updateByIdSelective(record, tokenUser.getSiteId(), tokenUser.getUserId());
                    }
                    // 正常
                    else {
                        AttendPunchRecordDO record = new AttendPunchRecordDO();
                        record.setId(attendPunchRecordDO.getId());
                        record.setPunchStatus(1);
//                        record.setStandardTime(inAttendPeriod.getEndPeriod());
//                        record.setHisStandardTime(attendPunchRecordDO.getStandardTime());
                        record.setHisPunchTime(attendPunchRecordDO.getPunchTime());
                        record.setHisPunchStatus(attendPunchRecordDO.getPunchStatus());

                        attendPunchRecordService.updateByIdSelective(record, tokenUser.getSiteId(), tokenUser.getUserId());
                    }
                }
            }


        }

        return 0;
    }

    /**
     * 保存考勤班次
     *
     * @param attendShiftList
     * @param tokenUser
     */
    private void saveAttendShift(String attendPlanId, List<AttendShiftSaveDTO> attendShiftList, TokenUser tokenUser) {

        for (AttendShiftSaveDTO attendShift : attendShiftList) {

            AttendShiftAddDTO attendShiftAddDTO = attendShift.to(AttendShiftAddDTO.class);
            attendShiftAddDTO.setPeriodJson(JSON.toJSONString(attendShift.getAttendPeriodList()));
            attendShiftAddDTO.setIsAdvanc(attendShift.getIsAdvanc());
            attendShiftAddDTO.setAttendPlanId(attendPlanId);

            if (attendShiftAddDTO.getEarliestPunchTime() == null) {
                attendShiftAddDTO.setEarliestPunchTime("80");
            }
            if (attendShiftAddDTO.getLatestPunchTime() == null) {
                attendShiftAddDTO.setLatestPunchTime("80");
            }

            attendShiftService.save(attendShiftAddDTO, tokenUser);
        }

    }

    /**
     * 保存排班周期
     *
     * @param attendPlanId
     * @param attendCycleList
     * @param tokenUser
     */
    private void saveAttendCycle(String attendPlanId, List<AttendCycleSaveDTO> attendCycleList, TokenUser tokenUser) {

        for (AttendCycleSaveDTO attendCycleSaveDTO : attendCycleList) {

            AttendShiftScheduleCycleAddDTO attendShiftScheduleCycle = new AttendShiftScheduleCycleAddDTO();

            attendShiftScheduleCycle.setAttendPlanId(attendPlanId);
            attendShiftScheduleCycle.setName(attendCycleSaveDTO.getCycleName());
            attendShiftScheduleCycle.setDaysJson(JSON.toJSONString(attendCycleSaveDTO.getCycleDays()));

            attendShiftScheduleCycleService.save(attendShiftScheduleCycle, tokenUser);
        }
    }

    /**
     * 保存人员排班
     *
     * @param attendPlanId
     * @param attendStaffScheduleList
     * @param tokenUser
     */
    private void saveAttendStaffSchedule(String attendPlanId, List<AttendStaffScheduleDTO> attendStaffScheduleList, TokenUser tokenUser) {

        for (AttendStaffScheduleDTO attendStaffScheduleDTO : attendStaffScheduleList) {

            AttendShiftStaffScheduleAddDTO attendShiftStaffScheduleAddDTO = new AttendShiftStaffScheduleAddDTO();
            attendShiftStaffScheduleAddDTO.setAttendPlanId(attendPlanId);
            attendShiftStaffScheduleAddDTO.setCompanyId("");
            attendShiftStaffScheduleAddDTO.setDeptInfoId("");
            attendShiftStaffScheduleAddDTO.setEmpInfoId(attendStaffScheduleDTO.getEmpInfoId());
            attendShiftStaffScheduleAddDTO.setYearly(attendStaffScheduleDTO.getYearMonthDay().split("-")[0]);
            attendShiftStaffScheduleAddDTO.setMonthly(attendStaffScheduleDTO.getYearMonthDay().split("-")[1]);
            attendShiftStaffScheduleAddDTO.setDaily(attendStaffScheduleDTO.getYearMonthDay().split("-")[2]);
            attendShiftStaffScheduleAddDTO.setAttendShiftName(attendStaffScheduleDTO.getShiftName());
            attendShiftStaffScheduleAddDTO.setType(attendStaffScheduleDTO.getType());

            attendShiftStaffScheduleService.save(attendShiftStaffScheduleAddDTO, tokenUser);
        }
    }

}
